using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace GraphMyCode.Controls
{
	internal class AnimationService
	{
		internal const double MaxZoomValue = 3;
		internal const double MinZoomValue = .01;
		private const double ZoomOutPercent = .5;
		private static readonly TimeSpan AnimationSpeed = TimeSpan.FromSeconds(.75);
		private readonly TranslateTransform dragTransform;
		private readonly PlaneProjection parentProjection;
		private readonly ScaleTransform zoomTransform;

		public AnimationService(ScaleTransform zoomTransform, TranslateTransform dragTransform,
								PlaneProjection parentProjection)
		{
			this.zoomTransform = zoomTransform;
			this.dragTransform = dragTransform;
			this.parentProjection = parentProjection;
		}

		public double GraphScale { get; set; }

		internal void MoveAnimated(double translateX, double translateY, double zoomValue, double oldZoomValue)
		{
			//zoomValue = zoomValue < MaxZoomValue ? zoomValue : MaxZoomValue;
			//double zoomOutValue = zoomValue*ZoomOutPercent;
			//zoomOutValue = zoomOutValue > 1 ? ZoomOutPercent : zoomOutValue;

			//Storyboard zoomOut = CreateZoomStoryboard(zoomOutValue);
			//Storyboard rotation = CreateRotationStoryboard(-45, 0, 0);
			//Storyboard translate = CreateTranslateStoryboard(translateX, translateY);
			//Storyboard zoom = CreateZoomStoryboard(zoomValue);
			//Storyboard rotationBack = CreateRotationStoryboard(0, 0, 0);

			//zoomOut.Completed += (s, e) => rotation.Begin();			
			//rotation.Completed += (s, e) => translate.Begin();
			//translate.Completed += (s, e) => zoom.Begin();
			//zoom.Completed += (s, e) => rotationBack.Begin();
			//rotationBack.Completed += (s, e) => OnAnimationFinished(translateX, translateY, zoomValue);

			//zoomOut.Begin();

			zoomValue = zoomValue < MaxZoomValue ? zoomValue : MaxZoomValue;

			Storyboard zoomOut = CreateZoomStoryboard(1.0 / (zoomValue * GraphScale));
			//Storyboard translateCenter = CreateTranslateStoryboard();
			//Storyboard rotation = CreateRotationStoryboard(-45, 0, 0);
			Storyboard translate = CreateTranslateStoryboard(translateX, translateY);
			Storyboard zoom = CreateZoomStoryboard(zoomValue);

			zoomOut.Completed += (s, e) => translate.Begin();
			//translateCenter.Completed += (s, e) => rotation.Begin();
			//rotation.Completed += (s, e) => translate.Begin();
			translate.Completed += (s, e) => zoom.Begin();
			zoom.Completed += (s, e) => OnAnimationFinished(translateX, translateY, zoomValue);

			zoomOut.Begin();
		}

		private Storyboard CreateRotateAndTranslateStoryboard(double rotationX, double rotationY, double rotationZ, double translateX, double translateY)
		{
			var rotation = new Storyboard();

			var rotationXAnimation = new DoubleAnimation
			{
				To = rotationX,
				Duration = new Duration(AnimationSpeed)
			};

			Storyboard.SetTarget(rotationXAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationXAnimation, new PropertyPath("RotationX"));

			var rotationYAnimation = new DoubleAnimation
			{
				To = rotationY,
				Duration = new Duration(AnimationSpeed)
			};

			Storyboard.SetTarget(rotationYAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationYAnimation, new PropertyPath("RotationY"));

			var rotationZAnimation = new DoubleAnimation
			{
				To = rotationZ,
				Duration = new Duration(AnimationSpeed)
			};

			Storyboard.SetTarget(rotationZAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationZAnimation, new PropertyPath("RotationZ"));

			var xAnimation = new DoubleAnimation
			{
				To = translateX,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(xAnimation, dragTransform);
			Storyboard.SetTargetProperty(xAnimation, new PropertyPath("X"));

			var yAnimation = new DoubleAnimation
			{
				To = translateY,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(yAnimation, dragTransform);
			Storyboard.SetTargetProperty(yAnimation, new PropertyPath("Y"));

			rotation.Children.Add(rotationXAnimation);
			rotation.Children.Add(rotationYAnimation);
			rotation.Children.Add(rotationZAnimation);
			rotation.Children.Add(xAnimation);
			rotation.Children.Add(yAnimation);

			return rotation;
		}

		private Storyboard CreateZoomTranslateStoryboard(double zoomValue,double translateX, double translateY)
		{
			var translate = new Storyboard();

			var xAnimation = new DoubleAnimation
			{
				To = translateX,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(xAnimation, dragTransform);
			Storyboard.SetTargetProperty(xAnimation, new PropertyPath("X"));

			var yAnimation = new DoubleAnimation
			{
				To = translateY,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(yAnimation, dragTransform);
			Storyboard.SetTargetProperty(yAnimation, new PropertyPath("Y"));

			var zoomXAnimation = new DoubleAnimation
			{
				To = zoomValue,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(zoomXAnimation, zoomTransform);
			Storyboard.SetTargetProperty(zoomXAnimation, new PropertyPath("ScaleX"));

			var zoomYAnimation = new DoubleAnimation
			{
				To = zoomValue,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(zoomYAnimation, zoomTransform);
			Storyboard.SetTargetProperty(zoomYAnimation, new PropertyPath("ScaleY"));

			translate.Children.Add(zoomXAnimation);
			translate.Children.Add(zoomYAnimation);
			translate.Children.Add(xAnimation);
			translate.Children.Add(yAnimation);
			return translate;
		}

		private Storyboard CreateTranslateStoryboard(double translateX, double translateY)
		{
			var translate = new Storyboard();

			var xAnimation = new DoubleAnimation
								{
									To = translateX,
									Duration = new Duration(AnimationSpeed)
								};
			Storyboard.SetTarget(xAnimation, dragTransform);
			Storyboard.SetTargetProperty(xAnimation, new PropertyPath("X"));

			var yAnimation = new DoubleAnimation
								{
									To = translateY,
									Duration = new Duration(AnimationSpeed)
								};
			Storyboard.SetTarget(yAnimation, dragTransform);
			Storyboard.SetTargetProperty(yAnimation, new PropertyPath("Y"));

			translate.Children.Add(xAnimation);
			translate.Children.Add(yAnimation);
			return translate;
		}

		private Storyboard CreateZoomStoryboard(double zoomValue)
		{
			var zoom = new Storyboard();

			var zoomXAnimation = new DoubleAnimation
									{
										To = zoomValue,
										Duration = new Duration(AnimationSpeed)
									};
			Storyboard.SetTarget(zoomXAnimation, zoomTransform);
			Storyboard.SetTargetProperty(zoomXAnimation, new PropertyPath("ScaleX"));

			var zoomYAnimation = new DoubleAnimation
									{
										To = zoomValue,
										Duration = new Duration(AnimationSpeed)
									};
			Storyboard.SetTarget(zoomYAnimation, zoomTransform);
			Storyboard.SetTargetProperty(zoomYAnimation, new PropertyPath("ScaleY"));

			zoom.Children.Add(zoomXAnimation);
			zoom.Children.Add(zoomYAnimation);
			return zoom;
		}

		private Storyboard CreateRotateAndZoomStoryboard(double rotationX, double rotationY, double rotationZ, double zoomValue, double translateX, double translateY)
		{
			var rotation = new Storyboard();

			var rotationXAnimation = new DoubleAnimation
			{
				To = rotationX,
				Duration = new Duration(AnimationSpeed)
			};

			Storyboard.SetTarget(rotationXAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationXAnimation, new PropertyPath("RotationX"));

			var rotationYAnimation = new DoubleAnimation
			{
				To = rotationY,
				Duration = new Duration(AnimationSpeed)
			};

			Storyboard.SetTarget(rotationYAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationYAnimation, new PropertyPath("RotationY"));

			var rotationZAnimation = new DoubleAnimation
			{
				To = rotationZ,
				Duration = new Duration(AnimationSpeed)
			};

			Storyboard.SetTarget(rotationZAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationZAnimation, new PropertyPath("RotationZ"));

			var zoomXAnimation = new DoubleAnimation
			{
				To = zoomValue,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(zoomXAnimation, zoomTransform);
			Storyboard.SetTargetProperty(zoomXAnimation, new PropertyPath("ScaleX"));

			var zoomYAnimation = new DoubleAnimation
			{
				To = zoomValue,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(zoomYAnimation, zoomTransform);
			Storyboard.SetTargetProperty(zoomYAnimation, new PropertyPath("ScaleY"));

			var xAnimation = new DoubleAnimation
			{
				To = translateX,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(xAnimation, dragTransform);
			Storyboard.SetTargetProperty(xAnimation, new PropertyPath("X"));

			var yAnimation = new DoubleAnimation
			{
				To = translateY,
				Duration = new Duration(AnimationSpeed)
			};
			Storyboard.SetTarget(yAnimation, dragTransform);
			Storyboard.SetTargetProperty(yAnimation, new PropertyPath("Y"));

			rotation.Children.Add(rotationXAnimation);
			rotation.Children.Add(rotationYAnimation);
			rotation.Children.Add(rotationZAnimation);
			rotation.Children.Add(zoomXAnimation);
			rotation.Children.Add(zoomYAnimation);
			rotation.Children.Add(xAnimation);
			rotation.Children.Add(yAnimation);
            
			return rotation;
		}

		private Storyboard CreateRotationStoryboard(double rotationX, double rotationY, double rotationZ)
		{
			var rotation = new Storyboard();

			var rotationXAnimation = new DoubleAnimation
										{
											To = rotationX,
											Duration = new Duration(AnimationSpeed)
										};

			Storyboard.SetTarget(rotationXAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationXAnimation, new PropertyPath("RotationX"));

			var rotationYAnimation = new DoubleAnimation
										{
											To = rotationY,
											Duration = new Duration(AnimationSpeed)
										};

			Storyboard.SetTarget(rotationYAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationYAnimation, new PropertyPath("RotationY"));

			var rotationZAnimation = new DoubleAnimation
										{
											To = rotationZ,
											Duration = new Duration(AnimationSpeed)
										};

			Storyboard.SetTarget(rotationZAnimation, parentProjection);
			Storyboard.SetTargetProperty(rotationZAnimation, new PropertyPath("RotationZ"));

			rotation.Children.Add(rotationXAnimation);
			rotation.Children.Add(rotationYAnimation);
			rotation.Children.Add(rotationZAnimation);

			return rotation;
		}

		protected virtual void OnAnimationFinished(double translateX, double translateY, double zoomValue)
		{
			if (AnimationFinished != null)
				AnimationFinished(this,
								  new AnimationFinishedEventArgs
									{
										TranslateX = translateX,
										TranslateY = translateY,
										ZoomValue = zoomValue
									});
		}

		internal event EventHandler<AnimationFinishedEventArgs> AnimationFinished;
	}

	internal delegate void AnimationDelegate(Storyboard first, Storyboard second);

	internal class AnimationFinishedEventArgs : EventArgs
	{
		public double ZoomValue { get; set; }

		public double TranslateX { get; set; }

		public double TranslateY { get; set; }
	}
}